package com.specter.mvc.web.spring;

import java.lang.reflect.Method;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ConventionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

	private static final String CONTROLLER_SUFFIX = "Controller";
	private String base_package;// cn.liangthink.edu
	private String package_locators;// controller
	// WebMvcAutoConfiguration config;

	public ConventionRequestMappingHandlerMapping() {
		this.setHandlerMethodMappingNamingStrategy(new ConventionRequestMappingNamingStrategy());
		log.info("------ 自动装载Controller配置完成！------ ");
	}

	@Override
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		RequestMappingInfo info = null;
		RequestMapping methodMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
		if (methodMapping != null) {// 方法注解后才执行

			String[] mps = resolveEmbeddedValuesInPatterns(methodMapping.value());
			if (mps.length == 0) {// 没有配置路径则自动生成路径
				mps = new String[] { this.createMethodMapping(method) };
			}
			info = createRequestMappingInfo(methodMapping, getCustomMethodCondition(method), mps);

			RequestMapping typeMapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
			if (typeMapping != null) {// 类没有配置 RequestMapping 则自动配置
				String[] tps = resolveEmbeddedValuesInPatterns(typeMapping.value());
				if (tps.length == 0) {
					tps = new String[] { this.createTypeMapping(handlerType) };
				}
				info = createRequestMappingInfo(typeMapping, getCustomTypeCondition(handlerType), tps).combine(info);

			} else {// 未配置 RequestMapping
				info = RequestMappingInfo.paths(createTypeMapping(handlerType)).build().combine(info);
			}
		}
		return info;
	}

	protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping,
			RequestCondition<?> customCondition, String[] patterns) {

		return RequestMappingInfo.paths(patterns).methods(requestMapping.method()).params(requestMapping.params())
				.headers(requestMapping.headers()).consumes(requestMapping.consumes())
				.produces(requestMapping.produces()).mappingName(requestMapping.name()).customCondition(customCondition)
				.build();
	}

	/**
	 * 将Controller类型转化成路径
	 */
	private String createTypeMapping(Class<?> handlerType) {
		StringBuilder sb = new StringBuilder();
		String name = handlerType.getName();
		name = (name.endsWith(CONTROLLER_SUFFIX) ? name.substring(0, name.lastIndexOf(CONTROLLER_SUFFIX)) : name);

		if (StringUtils.hasLength(base_package)) {
			name = name.substring(base_package.length());
		}
		if (StringUtils.hasLength(package_locators)) {
			name = StringUtils.replace(name, package_locators, "");
		}
		name = name.replace(".", "/");

		for (int i = 0; i < name.length(); i++) {
			if (i != 0 && Character.isLowerCase(name.charAt(i - 1)) && Character.isUpperCase(name.charAt(i))) {
				sb.append("-");
			}
			sb.append(Character.toLowerCase(name.charAt(i)));
		}
		return sb.toString();
	}

	/**
	 * 将Controller的方法转化成路径
	 */
	private String createMethodMapping(Method method) {
		StringBuilder sb = new StringBuilder();
		String name = method.getName();
		for (int i = 0; i < name.length(); i++) {
			if (i != 0 && Character.isLowerCase(name.charAt(i - 1)) && Character.isUpperCase(name.charAt(i))) {
				sb.append("-");
			}
			sb.append(Character.toLowerCase(name.charAt(i)));
		}
		return sb.toString();
	}

	public void setBase_package(String base_package) {
		this.base_package = base_package;
		if (StringUtils.hasLength(this.base_package) && !this.base_package.endsWith(".")) {
			this.base_package = this.base_package + ".";
		}
	}

	public void setPackage_locators(String package_locators) {
		this.package_locators = package_locators;
		if (StringUtils.hasLength(this.package_locators) && !this.package_locators.endsWith(".")) {
			this.package_locators = this.package_locators + ".";
		}
	}
}